package main

import (
	"crypto/md5"
	"fmt"
	"gitee.com/libbylg/pkgr/repo"
	"os"
	"path"
	"strings"
)

type CmdRehashOptions struct {
	Filter    *repo.ModuleLabelFilter
	Writeback bool
}

// NewCmdRehashOptions
// pkgr rehash   	[PATTERN] [--regex] [--plan PLAN-FILE] [--env ENV-NAME] [--writeback]
func NewCmdRehashOptions(argv []string) (*CmdRehashOptions, error) {
	// 检查参数数量
	if len(argv) < 2 {
		return nil, fmt.Errorf("the required parameter is missing, try -h for help")
	}

	// 初始化默认值
	opt := &CmdRehashOptions{
		Filter:    repo.NewModuleLabelFilter(),
		Writeback: false,
	}

	// 读取选项
	for index := 2; index < len(argv); index++ {
		// 是否按照正则表达式的方式去匹配
		if argv[index] == "--regex" {
			opt.Filter.Regex = true
			continue
		}

		// 指定 plan file 场景
		if argv[index] == "--plan" {
			if len(opt.Filter.PlanFile) != 0 {
				return nil, fmt.Errorf("the install plan file has been specified with `%v'", opt.Filter.PlanFile)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanFile = argv[index]
			continue
		}

		// 指定 plan env 场景
		if argv[index] == "--view" {
			if len(opt.Filter.PlanView) != 0 {
				return nil, fmt.Errorf("the plan env has been specified with `%v'", opt.Filter.PlanView)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanView = argv[index]
			continue
		}

		if argv[index] == "--devrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "devrepo"
			continue
		}

		if argv[index] == "--pkgrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "pkgrepo"
			continue
		}

		// 是否回写

		if argv[index] == "--writeback" {
			opt.Writeback = true
			continue
		}

		// 遇到无法识别的选项
		if strings.HasPrefix(argv[index], "-") {
			return nil, fmt.Errorf("unsupported options `%v'", argv[index])
		}

		// 识别 PATTERN 参数
		if len(opt.Filter.Pattern) == 0 {
			opt.Filter.Pattern = argv[index]
			continue
		}

		return nil, fmt.Errorf("unsupported option `%v'", argv[index])
	}

	// 整理
	opt.Filter.Tidy("pkgrepo")

	return opt, nil
}

func CmdRehash(argv []string) int {
	opt, err := NewCmdRehashOptions(argv)
	if err != nil {
		ERROR("Load option for `%v' failed: %v", "rehash", err.Error())
		return 1
	}

	// PKGREPO 必须存在
	if !repo.PathIsDir(repo.PKGREPO) {
		ERROR("The environment variable `$PKGREPO' is missing")
		return 1
	}

	moduleLabelList, err := repo.SelectModuleLabels(opt.Filter)
	if err != nil {
		ERROR("Filter modules failed: %v", err.Error())
		return 1
	}

	if len(moduleLabelList) == 0 {
		WARNI("no module matched")
		return 1
	}

	allFailCount := 0

	for _, moduleLabel := range moduleLabelList {
		// 读取该模块的 VERSION 文件
		descriptor, err := repo.ReadModuleVersionDescription(moduleLabel.String())
		if err != nil {
			WARNI("Load module version description file for `%v' failed: %v", moduleLabel.String(), err.Error())
			allFailCount++
			continue
		}
		// 确定该版本的 module 的安装路径
		modverDir := path.Join(repo.PKGREPO, moduleLabel.ModuleName, moduleLabel.ModuleVersion)

		// 创建一个 HASH 计算器
		hash := md5.New()

		// 对每个包计算 md5
		failCount := 0

		// 如果该模块没有包，没必要处理了
		if len(descriptor.ModulePackages) == 0 {
			fmt.Fprintf(os.Stdout, "%-25v %-35v %-4v %v\n", moduleLabel.String(), "-", "SKIP", "NO-PACKAGE")
			allFailCount++
			continue
		}

		for _, pkg := range descriptor.ModulePackages {
			// 无包的特殊情况
			if (pkg.PackageName == "-") || (pkg.PackageName == "") {
				fmt.Fprintf(os.Stdout, "%-25v %-35v %-4v %v\n", moduleLabel.String(), "-", "SKIP", "NO-PACKAGE")
				continue
			}

			// 给包文件生成hash
			md5HashString, err := repo.GenFileHash(hash, path.Join(modverDir, pkg.PackageName))
			if err != nil {
				fmt.Fprintf(os.Stdout, "%-25v %-35v %-4v %v\n", moduleLabel.String(), pkg.PackageName, "FAIL", fmt.Sprintf("GEN-HASH-FAIL:%v", err))
				failCount++
				continue
			}

			md5HashString = "MD5:" + md5HashString

			// 如果以前无 HASH
			if pkg.HASH == "-" || pkg.HASH == "" {
				fmt.Fprintf(os.Stdout, "%-25v %-35v %-4v %v\n", moduleLabel.String(), pkg.PackageName, "OK", md5HashString)
			} else {
				// 做一个比较，如果不想等，给个提示
				if md5HashString != pkg.HASH {
					fmt.Fprintf(os.Stdout, "%-25v %-35v %-4v %v\n", moduleLabel.String(), pkg.PackageName, "OK", fmt.Sprintf("%v MISMATCH(%v)", md5HashString, pkg.HASH))
				} else {
					fmt.Fprintf(os.Stdout, "%-25v %-35v %-4v %v\n", moduleLabel.String(), pkg.PackageName, "OK", md5HashString)
				}
			}

			// hash 生成成功
			pkg.HASH = md5HashString
		}

		allFailCount += failCount

		// 只有全部计算成功，才会回写
		if failCount == 0 {
			if opt.Writeback {
				err := repo.WriteModuleVersionDescription(descriptor)
				if err != nil {
					WARNI("Writeback VERSION file for `%v' failed: %v", moduleLabel.String(), err.Error())
					continue
				}
			}
		}
	}

	if allFailCount != 0 {
		return 1
	}

	return 0
}
